package top.lixunda.ecommerce.server.good.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.common.utils.StringUtils;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStore;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStoreUser;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageDTO;
import top.lixunda.ecommerce.server.business.api.entity.QiNiuCallbackBody;
import top.lixunda.ecommerce.server.good.api.entity.db.GoodProduceDO;
import top.lixunda.ecommerce.server.good.api.entity.db.QiNiuFileDO;
import top.lixunda.ecommerce.server.good.api.entity.dto.GoodProduceInsertDTO;
import top.lixunda.ecommerce.server.good.api.entity.dto.GoodProduceQueryDTO;
import top.lixunda.ecommerce.server.good.api.entity.dto.GoodProduceUpdateDTO;
import top.lixunda.ecommerce.server.good.config.QiNiuConfig;
import top.lixunda.ecommerce.server.good.mapper.GoodProduceMapper;
import top.lixunda.ecommerce.server.good.service.IGoodProduceService;
import top.lixunda.ecommerce.server.good.service.IQiNiuFileService;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 商品描述，放在详情页商品基本信息下方
 *
 * @author lixunda
 * @version time:2020/3/11 12:47
 */
@Service
public class GoodProduceServiceImpl extends BaseServiceImpl<GoodProduceMapper, GoodProduceDO>
        implements IGoodProduceService {

    private final QiNiuConfig qiNiuConfig;

    private final IQiNiuFileService qiNiuFileService;

    @Autowired
    public GoodProduceServiceImpl(QiNiuConfig qiNiuConfig,
                                  IQiNiuFileService qiNiuFileService) {
        this.qiNiuConfig = qiNiuConfig;
        this.qiNiuFileService = qiNiuFileService;
    }

    /**
     * 根据id查询商品介绍内容信息
     *
     * @param id 商品介绍内容编号
     * @return 商品介绍内容信息
     */
    @Override
    public GoodProduceDO queryGoodProduceById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("商品介绍内容编号不能为空");
        }
        return this.getById(id);
    }

    /**
     * 批量查询，根据id查询商品介绍内容信息
     *
     * @param ids 商品介绍内容编号
     * @return 商品介绍内容信息
     */
    @Override
    public List<GoodProduceDO> queryGoodProduceByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("商品介绍内容编号不能为空");
        }
        return this.list(new LambdaQueryWrapper<GoodProduceDO>()
                .in(GoodProduceDO::getId, ids)
                .orderByAsc(GoodProduceDO::getSortNumber)
                .orderByAsc(GoodProduceDO::getUpdateTime));
    }

    /**
     * 根据商品id查询商品介绍内容信息
     *
     * @param id 商品编号
     * @return 商品介绍内容信息
     */
    @Override
    public List<GoodProduceDO> queryGoodProduceByGoodId(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("商品编号不能为空");
        }
        return this.list(new LambdaQueryWrapper<GoodProduceDO>()
                .eq(GoodProduceDO::getGoodId, id)
                .orderByAsc(GoodProduceDO::getSortNumber)
                .orderByAsc(GoodProduceDO::getUpdateTime));
    }

    /**
     * 条件分页查询商品介绍信息
     *
     * @param pageDTO 条件分页查询数据
     * @return 分页查询数据
     */
    @Override
    public IPage<GoodProduceDO> queryGoodProduceWrapperPage(PageDTO<GoodProduceDO, GoodProduceQueryDTO> pageDTO) {
        if (ObjectValidators.isEmpty(pageDTO)) {
            throw getAppException("分页查询参数不能为空");
        }
        return this.page(pageDTO.getPage(), pageDTO.getWrapper(
                wrapper -> wrapper.orderByAsc(GoodProduceDO::getSortNumber)
                        .orderByAsc(GoodProduceDO::getUpdateTime)));
    }

    /**
     * 插入一条商品介绍内容信息，图片类型专用
     *
     * @param files                图片文件，批量
     * @param goodProduceInsertDTO 插入数据
     * @return 插入后的商品介绍内容信息
     */
    @Override
    public List<GoodProduceDO> insertGoodProduceWithFile(MultipartFile[] files, GoodProduceInsertDTO goodProduceInsertDTO) {
        if (ObjectValidators.isEmpty(goodProduceInsertDTO)) {
            throw getAppException("参数不能为空");
        }
        if (ObjectValidators.isEmpty(files)) {
            throw getAppException("图片不能为空");
        }
        if (ObjectValidators.isEmpty(goodProduceInsertDTO.getContent()) ||
                !goodProduceInsertDTO.getContentType().equals(GoodProduceDO.CONTENT_TYPE_IMAGE)) {
            throw getAppException("该方法只支持图片类型，其他类型请使用insertGoodProduce接口");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStore cacheStore = currentStoreCacheNotNull();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        List<GoodProduceDO> insertList = Arrays.stream(files)
                .map(item -> {
                    // 上传图片
                    String name = StringUtils.randomFileName(item);
                    QiNiuCallbackBody qiNiuCallbackBody;
                    try {
                        qiNiuCallbackBody = uploadQiNiuFile(item.getInputStream(), String.valueOf(cacheStoreUser.getAccount()), name);
                    } catch (IOException e) {
                        e.printStackTrace();
                        throw getAppException("保存图片出错: " + e.getMessage());
                    }
                    QiNiuFileDO qiNiuFileDO = new QiNiuFileDO();
                    BeanUtils.copyProperties(
                            createQiNiuDo(qiNiuCallbackBody),
                            qiNiuFileDO);
                    qiNiuFileDO.setCreateTime(LocalDateTime.now())
                            .setUserId(cacheStoreUser.getAccount())
                            .setUserType(QiNiuFileDO.USER_TYPE_STORE);
                    boolean success = qiNiuFileService.save(qiNiuFileDO);
                    if (!success) {
                        throw getAppException("保存图片信息错误");
                    }

                    // 保存商品介绍内容信息
                    GoodProduceDO goodProduceDO = new GoodProduceDO();
                    goodProduceDO.setCreateTime(localDateTime)
                            .setCreateUserId(cacheStoreUser.getAccount())
                            .setCreateUserName(cacheStoreUser.getName())
                            .setUpdateTime(localDateTime)
                            .setUpdateUserId(cacheStoreUser.getAccount())
                            .setUpdateUserName(cacheStoreUser.getName())
                            .setGoodId(goodProduceInsertDTO.getGoodId())
                            .setStoreId(cacheStore.getId())
                            .setLinkGoodId(goodProduceInsertDTO.getLinkGoodId())
                            .setLinkSubGoodId(goodProduceInsertDTO.getLinkSubGoodId())
                            .setLinkUrl(goodProduceInsertDTO.getLinkUrl())
                            .setSortNumber(goodProduceInsertDTO.getSortNumber())
                            .setRemark(goodProduceInsertDTO.getRemark())
                            .setContentType(GoodProduceDO.CONTENT_TYPE_IMAGE)
                            .setImage(qiNiuConfig.getBaseUrl() + qiNiuFileDO.getFileKey())
                            .setImageFileId(qiNiuFileDO.getId());
                    return goodProduceDO;
                })
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(insertList)) {
            throw getAppException("请求错误, 插入数据为空");
        }
        // 插入商品内容数据
        boolean success = this.saveBatch(insertList);
        if (!success) {
            throw getAppException("插入数据失败");
        }
        List<Integer> ids = insertList.stream()
                .map(GoodProduceDO::getId)
                .collect(Collectors.toList());
        return (List<GoodProduceDO>) this.listByIds(ids);
    }

    /**
     * 插入一条商品介绍内容信息，不能插入图片类型的商品介绍信息
     *
     * @param list 插入数据
     * @return 插入后的商品介绍内容信息
     */
    @Override
    public List<GoodProduceDO> insertGoodProduce(List<GoodProduceInsertDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("插入数据不能为空");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStore cacheStore = currentStoreCacheNotNull();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        List<GoodProduceDO> insertList = list.stream()
                .map(item -> {
                    GoodProduceDO goodProduceDO = new GoodProduceDO();
                    goodProduceDO.setCreateTime(localDateTime)
                            .setCreateUserId(cacheStoreUser.getAccount())
                            .setCreateUserName(cacheStoreUser.getName())
                            .setUpdateTime(localDateTime)
                            .setUpdateUserId(cacheStoreUser.getAccount())
                            .setUpdateUserName(cacheStoreUser.getName())
                            .setGoodId(item.getGoodId())
                            .setStoreId(cacheStore.getId())
                            .setLinkGoodId(item.getLinkGoodId())
                            .setLinkSubGoodId(item.getLinkSubGoodId())
                            .setLinkUrl(item.getLinkUrl())
                            .setSortNumber(item.getSortNumber())
                            .setRemark(item.getRemark());
                    switch (item.getContentType()) {
                        case GoodProduceDO.CONTENT_TYPE_TEXT:
                            goodProduceDO.setContentType(GoodProduceDO.CONTENT_TYPE_TEXT)
                                    .setContent(item.getContent());
                            break;
                        case GoodProduceDO.CONTENT_TYPE_RICH_TEXT:
                            goodProduceDO.setContentType(GoodProduceDO.CONTENT_TYPE_RICH_TEXT)
                                    .setRichTextContent(item.getContent());
                            break;
                        case GoodProduceDO.CONTENT_TYPE_IMAGE:
                            throw getAppException("该方法不支持图片类型，图片类型请使用insertGoodProduceWithFile接口");
                        default:
                            throw getAppException("错误的类型：" + item.getContentType());
                    }
                    return goodProduceDO;
                })
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(insertList)) {
            throw getAppException("请求错误, 插入数据为空");
        }
        boolean success = this.saveBatch(insertList);
        if (!success) {
            throw getAppException("插入数据失败");
        }
        List<Integer> ids = insertList.stream()
                .map(GoodProduceDO::getId)
                .collect(Collectors.toList());
        return (List<GoodProduceDO>) this.listByIds(ids);
    }

    /**
     * 根据商品介绍内容编号更改商品介绍内容信息
     *
     * @param list 更改数据
     * @return 更改后的商品介绍内容信息
     */
    @Override
    public List<GoodProduceDO> changeGoodProduceById(List<GoodProduceUpdateDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("修改数据参数不能为空");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodProduceDO> updateList = list.stream()
                .map(item -> {
                    if (ObjectValidators.isEmpty(item) || ObjectValidators.isEmpty(item.getId())) {
                        throw getAppException("参数错误：更改数据或商品内容编号不能为空");
                    }
                    GoodProduceDO goodProduceDO = this.getById(item.getId());
                    if (ObjectValidators.isEmpty(goodProduceDO)) {
                        throw getAppException("商品介绍内容信息不存在: id = " + item.getId());
                    }
                    if (ObjectValidators.isEmpty(goodProduceDO.getStoreId()) ||
                            !goodProduceDO.getStoreId().equals(cacheStore.getId())) {
                        throw getAppException("权限不足，只能更改本人店铺的数据");
                    }
                    goodProduceDO.setUpdateTime(localDateTime)
                            .setUpdateUserId(cacheStoreUser.getAccount())
                            .setUpdateUserName(cacheStoreUser.getName())
                            .setLinkGoodId(item.getLinkGoodId())
                            .setLinkSubGoodId(item.getLinkSubGoodId())
                            .setLinkUrl(item.getLinkUrl())
                            .setSortNumber(item.getSortNumber())
                            .setRemark(item.getRemark());
                    switch (goodProduceDO.getContentType()) {
                        case GoodProduceDO.CONTENT_TYPE_TEXT:
                            goodProduceDO.setContent(item.getContent());
                            break;
                        case GoodProduceDO.CONTENT_TYPE_RICH_TEXT:
                            goodProduceDO.setRichTextContent(item.getContent());
                            break;
                        default:
                    }
                    return goodProduceDO;
                })
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(updateList)) {
            throw getAppException("请求错误, 修改数据为空");
        }
        boolean success = this.updateBatchById(updateList);
        if (!success) {
            throw getAppException("修改数据失败");
        }
        List<Integer> ids = updateList.stream()
                .map(GoodProduceDO::getId)
                .collect(Collectors.toList());
        return (List<GoodProduceDO>) this.listByIds(ids);
    }

    /**
     * 根据商品介绍内容编号移除商品介绍内容信息
     *
     * @param ids 商品介绍内容编号
     * @return 是否移除成功
     */
    @Override
    public boolean removeGoodProduceByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("商品介绍内容编号不能为空");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        CacheStore cacheStore = currentStoreCacheNotNull();
        this.update(new LambdaUpdateWrapper<GoodProduceDO>()
                .set(GoodProduceDO::getRemoveTime, localDateTime)
                .set(GoodProduceDO::getRemoveUserId, cacheStoreUser.getAccount())
                .set(GoodProduceDO::getRemoveUserName, cacheStoreUser.getName())
                .in(GoodProduceDO::getId, ids)
                .eq(GoodProduceDO::getStoreId, cacheStore.getId()));
        this.remove(new LambdaUpdateWrapper<GoodProduceDO>()
                .in(GoodProduceDO::getId, ids)
                .eq(GoodProduceDO::getStoreId, cacheStore.getId()));
        return true;
    }
}
